package com.sjsu.aws.primitve.client.doublebarrier;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import com.sjsu.aws.doublebarrier.DoubleBarrier;
import com.sjsu.aws.doublebarrier.DoubleBarrierLifeCycle;
import com.sjsu.aws.utils.SessionIdGenerator;
import com.sjsu.aws.utils.UUIDGenerator;

/**
 * 
 * @author Pawar Deepali
 * 
 */
public class ClientDoubleBarrier {
	private static final Log	 LOG	                      = LogFactory
	                                                                  .getLog(ClientDoubleBarrier.class);
	private static final Integer	PARTICIPANT_COUNT	      = 3;
	private static long	         timeout	                  = 50000;
	private static long	         waitTimeForOtherThreadToJoin	= 10000;
	
	public static void main(String args[]) {
		ClientDoubleBarrier clientDoubleBarrier = new ClientDoubleBarrier();
		try {
			clientDoubleBarrier.barrierShouldBeRunWithoutProblems();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	
	public void barrierShouldBeRunWithoutProblems() throws Exception {
		ExecutorService executorService = runBarrierClientsAsMuchAsExpectedCount();
		executorService.shutdown();
		executorService.awaitTermination(200, TimeUnit.SECONDS);
	}
	
	public void barrierShouldBeRunWithoutProblems_When_ItIsRepeatlyRun()
	        throws Exception {
		final Integer repeatCount = 30;
		for (int i = 0; i < repeatCount; i++) {
			barrierShouldBeRunWithoutProblems();
		}
	}
	
	private ExecutorService runBarrierClientsAsMuchAsExpectedCount() {
		ExecutorService executorService = Executors
		        .newFixedThreadPool(PARTICIPANT_COUNT);
		String barrierId = UUIDGenerator.getUUID();
		for (int i = 0; i < PARTICIPANT_COUNT; i++) {
			System.out.println("Calling i " + i);
			executorService.execute(new BarrierClient(barrierId, timeout));
		}
		return executorService;
	}
	
	private class BarrierClient implements Runnable {
		private String	barrierId;
		private long	timeout;
		
		public BarrierClient(String barrierId, long timeout) {
			this.barrierId = barrierId;
			this.timeout = timeout;
			
		}
		
		@Override
		public void run() {
			try {
				DoubleBarrier db = new DoubleBarrier();
				db.setBarrierId(barrierId);
				String participantId = new SessionIdGenerator().generateId(10);
				String jobId = new SessionIdGenerator().generateId(10);
				db.setJobId(jobId);
				db.setParticipantId(participantId);
				
				DoubleBarrierLifeCycle doubleBarrierLifeCycle = new DoubleBarrierLifeCycle(
				        PARTICIPANT_COUNT, participantId, db, timeout);
				doubleBarrierLifeCycle.ensureAllParticipantsAreReady();
				doubleBarrierLifeCycle.ensureAllParticipantsStartTheirJobs();
				Thread.sleep(waitTimeForOtherThreadToJoin);
				doubleBarrierLifeCycle.leave();
				// LOG.info("End of TID : " + Thread.currentThread().getId());
			} catch (Exception e) {
				throw new RuntimeException(e.toString(), e);
			}
		}
	}
}
